from Library import *
from Utils.PListParser import *
from Player import *
from Services.Uploader import *
from Services.MusicSyncer import *
from Utils.utils import *
import urllib

class RemoteTrack(Track):
	def __init__(self,library):
		Track.__init__(self)
		self.library = library
		self.remote = True
		self.lsongs = True
		self.isStream = True

	def getImage(self):
		return None
	def setImage(self,image):
		pass
	image = property(getImage,setImage)

	def play(self,playlist = None):
		print "going to play",self.stream
		LMusicPlayer.playTrack(self,self.library,playlist)
	
	def pause(self):
		LMusicPlayer.pause()
	
	def fetchStream(self):
		pass
	
class RemotePlaylist(Playlist):
	def __init__(self,library):
		Playlist.__init__(self,library)
		#self._tracks = {}
		self.fetchedTracks = False
		self.master = False
	
	def setInfo(self,plist):
		try:
			#print self._tracks
			#print "setting info in",self.name,"to",plist
			#print "I have",self.trackCount(),'tracks'
			#print 'I have duration',self.totalDuration()
			#print
			try:
				if self.fetchedTracks:
					myTrackCount = self.trackCount()
					theirTrackCount = plist['Track Count']
					myDuration = self.totalDuration()
					theirDuration = plist['Duration']
					if myTrackCount!=theirTrackCount:
						if theirDuration and myDuration!=theirDuration:
							self.fetchTracks()
			except: pass
		except: pass

	def url(self):
		return self._library.url()+("playlist?%d" % self.playlistID)

	def fetchTracks(self):
		print "fetching tracks for remote playlist",self.name
		self.fetchedTracks = False # blocks!
		url = self.url()
		#print "url=",url
		playlistXMLData = urllib.urlopen(url).read()
		#print playlistXMLData
		playlistData = PListReader().parseString(playlistXMLData)
		try:
			plist = playlistData[0]
			#print "fetch plist",plist
			self.setTracksPList(plist)
			self.fetchedTracks = True
		except:
			#print "failed to setTracksPList"
			pass
	
	def setTracksPList(self,plist):
		#print plist
		if plist.has_key('Playlist Items'):
			items = plist['Playlist Items']
			incomingTracks = {}
			#self._tracks = {}
			for item in items:
				track = RemoteTrack(self._library)
				item['Location'] = self._library.url()+("stream?%d" % item['Track ID'])
				track.setPList(item)
				track.stream = track.location
				incomingTracks[track.trackID] = track
				if not self.containsTrackID(track.trackID):
					#print "adding remote track",track.trackID
					self._library._tracks[track.trackID] = track
					self.addTrackID(track.trackID)
			for trackID in self.trackIDs:
				try: incomingTracks[trackID]
				except:
					#print "removing remote track",track.trackID
					self.removeTrackID(trackID)

	def setPList(self,pList):
		try: self.playlistID = pList.get('Playlist ID')
		except: pass
		self.name = unikode(pList.get('Name','Unknown'))
		self.master = pList.get('Master',False)
		self.trash = pList.get('Trash',False)
		self.purchased = pList.get('Purchased Music',False)
		self.smart = pList.get('Smart',False)
		self.shared = pList.get('Shared',False)

	def getPList(self):
		print "RemotePlaylist building remote plist"
	
	def uploadTracks(self,tracks):
		LMusicUploader.singleton().uploadTracks(tracks,self,self.library())
		#print "uploading tracks to",self._library.url()
		
class RemoteLibrary(Library):
	def __init__(self,name,address,port):
		Library.__init__(self)
		self.name = name
		self.address = address
		self.port = port
		self.didFetchPlaylists = False
		self.allowWrites = False
		self.fetchTimer = QTimer()
		self.timeoutTimer = QTimer()
		self.job = None
		self.fetchData = None
		QObject.connect(self.fetchTimer,SIGNAL("timeout()"),self.startFetchPlaylists)
		QObject.connect(self.timeoutTimer,SIGNAL("timeout()"),self.abortFetchPlaylists)
		self.fetchTimer.start(5*1000)
	
	def url(self):
		return "http://%s:%s/" % (self.address,self.port)

	def emptyPlaylist(self):
		return RemotePlaylist(self)

	def startFetchPlaylists(self):
		#print "fetching playlists for",self.name
		self.fetchTimer.stop()
		url = self.url()+"playlists"
		kurl = KURL(url)
		self.job = KIO.get(kurl,False,False)
		self.job.suspend()
		self.fetchData = ""
		#self.emit(SIGNAL('startLoadingPage(QString &)'),kurl.url())
		QObject.connect(self.job,SIGNAL('data(KIO::Job *,const QByteArray &)'),self.onFetchData)
		QObject.connect(self.job,SIGNAL('result(KIO::Job *)'),self.onFetchResult)
		self.job.resume()
		self.timeoutTimer.start(30*1000)

	def onFetchData(self,job,bytes):
		#print "RemoteLibrary: onFetchData"
		self.fetchData = self.fetchData+unikode(QString(bytes))
	
	def onFetchResult(self,job):
		#print "RemoteLibrary: onFetchResult"
		self.timeoutTimer.stop()
		if len(self.fetchData)>0:
			playlistsData = PListReader().parseString(self.fetchData)
			if playlistsData:
				#print playlistsData
				playlistsData = playlistsData[0]
				self.allowWrites = playlistsData.get('Share Allow Writes',False)
				self.setPList(playlistsData)
				self.didFetchPlaylists = True
				self.emit(PYSIGNAL("fetchedPlaylists"),(self,None))
			self.fetchTimer.start(20*1000)
		else:
			self.emit(PYSIGNAL('unmount'),(self,None))

	def abortFetchPlaylists(self):
		self.job = None
		self.timeoutTimer.stop()
		self.emit(PYSIGNAL('unmount'),(self,None))

##
## XXX DSM old synchronous code
##
##	def fetchPlaylists(self):
##		print "fetching playlists for",self.name
##		try:
##			playlistsXMLData = urllib.urlopen(self.url()+"playlists").read()
##			if playlistsXMLData:
##				playlistsData = PListReader().parseString(playlistsXMLData)
##				if playlistsData:
##					#print playlistsData
##					playlistsData = playlistsData[0]
##					self.allowWrites = playlistsData.get('Share Allow Writes',False)
##					self.setPList(playlistsData)
##					self.didFetchPlaylists = True
##					self.emit(PYSIGNAL("fetchedPlaylists"),(self,None))
##		except:
##			self.timer.stop()
##			self.emit(PYSIGNAL('unmount'),(self,None))
	
	def getPlaylists(self):
		#if not self.didFetchPlaylists:
		#	self.fetchPlaylists()
		return Library.getPlaylists(self)

	#
	# the implementation here is slightly different than normal because it's done periodically
	# and we're interested in the differences.  This strategy may find itself elsewhere as we
	# shift Lsongs to a more client/server model overall
	#
	def setPList(self,pList):
		if pList.has_key('Playlists'):
			# add any new playlists
			playlists = pList['Playlists']
			playlistNames = []
			for playlistPList in playlists:
				playlistName = playlistPList['Name']
				playlistNames.append(playlistName)
				playlist = self.playlistWithName(playlistName)
				if playlist==None:
					playlist = self.emptyPlaylist()
					playlist.setPList(playlistPList)
					self._playlists.append(playlist)
					#print "adding playlist",playlist.name
					self.emit(PYSIGNAL('addedPlaylist'),(self,playlist))
				playlist.setInfo(playlistPList)
			# remove any deleted playlists
			for playlist in self._playlists[:]:
				try: index = playlistNames.index(playlist.name)
				except: self.removePlaylist(playlist)

	def addNewPlaylist(self,name = None,master=False,trash=False):
		try:
			url = self.url()+"createPlaylist?"+urllib.quote(name)
			urllib.urlopen(url).read()
		except: pass

	def syncWith(self,library):
		LMusicSyncer.singleton().syncLibraries(self,library)
		
